﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace VRP_GTS
{
    [Serializable()]
    class CVRPSolution
    {
        public double TotalCost { get; set; }

        public double TotalCostWithPenalty { get; set; }

        public List<Path> TourList { get; set; }


        internal void WriteToFile(string p, TimeSpan ts)
        {
            StreamWriter file = new StreamWriter(p);

            for (int i = 0; i < TourList.Count; i++)
                TourList[i].WriteToFile(i + 1, file);
            file.WriteLine("Cost " + TotalCost);
            file.WriteLine("Time " + ts.TotalSeconds + "secs");
            file.Close();
        }

        // calculate the total cost
        public double GetTotalCost()
        {
            TotalCost = 0;
            foreach (Path route in TourList)
                TotalCost += route.Length;

            return TotalCost;
        }

        // calculate the total cost with penalty term
        public double GetTotalCostWithPenalty(double capacity)
        {
            TotalCostWithPenalty = TotalCost;
            foreach (Path route in TourList)
                TotalCostWithPenalty += Heuristics.alphaCap * Math.Max(0, route.Load - capacity);

            return TotalCostWithPenalty;
        }

        // if the capacity constraint is violated, return 1; otherwise, return 0
        public int CheckCapacityConstraint(double capacity)
        {
            foreach (Path route in TourList)
                if (route.Load > capacity)
                    return 1;

            return 0;
        }

        internal void CheckFeasibility(CVRPData vrpData)
        {
            double capacity = vrpData.Capacity;
            double? maxLength = vrpData.MaxLength;
            int n = vrpData.Dimension;
            double? bestKnownSolution = vrpData.BestKnownSolution;
            int flag = 0;
            int[] nodes = new int[n];

            if (TotalCost < bestKnownSolution)
            {
                flag = 1;
                Console.WriteLine("The objective value is below the best known solution.");
            }

            for (int i = 0; i < TourList.Count; i++)
            {
                if (TourList[i].Load > capacity)
                {
                    flag = 1;
                    Console.WriteLine("Route #{0} is over the capacity.", i + 1);
                }

                if (TourList[i].Length > maxLength)
                {
                    flag = 1;
                    Console.WriteLine("Route #{0} is over the max length.", i + 1);
                }

                if (TourList[i].AllNodes[0].Id != 0 || TourList[i].AllNodes[TourList[i].AllNodes.Count - 1].Id != 0)
                {
                    flag = 1;
                    Console.WriteLine("Depot is not included in the route #{0}.", i + 1);
                }

                for (int j = 1; j < TourList[i].AllNodes.Count - 1; j++)
                {
                    nodes[TourList[i].AllNodes[j].Id]++;
                }
            }

            for (int i = 1; i < n; i++)
            {
                if (nodes[i] == 0)
                {
                    flag = 1;
                    Console.WriteLine("Node {0} is not included in the routes.", i);
                }

                if (nodes[i] > 1)
                {
                    flag = 1;
                    Console.WriteLine("Node {0} is included {1} times.", i, nodes[i]);
                }
            }

            if (flag == 0)
                Console.WriteLine("Solution is valid.");
            else
                Console.WriteLine("Solution is not valid.");
        }
    }
}
